/**
 * @file    wincesrv_form.cpp
 * @brief   Main dialog of woshcesrv application
 *
 *
 *
 ****************************************************************************
 * @version $Id: wincesrv_form.cpp 2808 2010-07-28 20:44:00Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

 #include "wincesrv_form.h"

 #include <core/Bundle.h>
 #include <core/Request.h>
 #include <core/Response.h>
 #include <core/BusConnector.h>
 #include <core/SecurityManager.h>
 #include <core/NetworkManager.h>
 #include <core/Utilities.h>
 #include <core/wince/stringutils.h>
 #include <interfaces/services/DiscoveryUdp.h>
 #include <interfaces/services/CommunicatorService.h>

using namespace std;
using namespace wosh;
//////////////////////////////////////////////////////////////////

extern HINSTANCE g_hInst;	///< Local copy of hInstance
extern LPCTSTR _wosh_winCE_title;	///< title of main dialog

HWND g_hWndMenuBar;		///< Handle to menu bar #2
BOOL g_fChecked_Sk;		///< True if "Disable SoftKey" is checked
BOOL g_fChecked_Swap;	///< True if "Swap SoftKeys" is checked
BOOL g_fChecked_Quit;	///< True if "Disable Options->Quit" is checked
UINT g_uiSk_Id;		///< The current command ID of the action Softkey on Menubar 2

//////////////////////////////////////////////////////////////////

BusConnector BusCore;	///< connect to Bus..
DialogListener formDialogListener;

//////////////////////////////////////////////////////////////////
// local scope declarations

void postMessage( Message* message );
void processBusMessages( const HWND hWnd );

BOOL ProcessCheckBox( const HWND hWnd, const WPARAM wParam );
BOOL OnMenuPopup( const HWND hWnd, const WPARAM wParam );
BOOL OnCommand( const HWND hWnd, const WPARAM wParam );


BOOL InitDialog( const HWND hDlg );

BOOL UncheckAll( const HWND hWnd );
BOOL ProcessListBox( const HWND hWnd );

BOOL ProcessSkCheckBox();


//////////////////////////////////////////////////////////////////


BOOL CALLBACK DialogProc( const HWND hWnd, const UINT Msg, const WPARAM wParam, const LPARAM lParam ) 
 {
	BOOL bProcessedMsg = TRUE;
	switch (Msg) {
		case WM_INITDIALOG: {
			if (FALSE == InitDialog(hWnd)) {
				EndDialog(hWnd, -1);
			 }
			else {
				BusCore.connect( _Bus_Core );
				BusCore.setMessageHandler(&formDialogListener);
			 }
			return TRUE;
			}
		case WM_CLOSE: {
			BusCore.disconnect();
			BusCore.setMessageHandler(NULL);
			EndDialog(hWnd, 0);
			return TRUE;
			}
		case WM_ACTIVATE: {
			if (WA_INACTIVE != LOWORD(wParam)) {
				SetFocus(hWnd);
			 }
			break;
			}
		case WM_INITMENUPOPUP: { // called before the menu pops up
			OnMenuPopup(hWnd, wParam);
			return TRUE;
			}
		case WM_COMMAND: {
			bProcessedMsg = OnCommand( hWnd, wParam );
			break;
			}
		default: {
			bProcessedMsg = FALSE;
			break;
			}
	 }

	processBusMessages(hWnd);

	return bProcessedMsg;
 }

/**
 * @brief   Initialize the proper settings to create the dialog.
 */
BOOL InitDialog( const HWND hWnd )
 {
	HWND hListBox;
	LRESULT lResult;
	TCHAR psz[80];
	ZeroMemory(psz, sizeof(psz));

	// initialize dialog box, specifying that it should stretch full screen
	SHINITDLGINFO sid;
	ZeroMemory(&sid, sizeof(sid));
	sid.dwMask = SHIDIM_FLAGS;
	sid.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
	sid.hDlg = hWnd;

	// initialize menubar
	SHMENUBARINFO mbi;
	ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
	mbi.cbSize = sizeof(SHMENUBARINFO);
	mbi.hwndParent = hWnd;
	mbi.nToolBarId = IDR_MENU_MENU2;
	mbi.hInstRes = g_hInst;

	if ( FALSE == SHCreateMenuBar(&mbi) ) {
		return FALSE;
	 }
	g_hWndMenuBar = mbi.hwndMB;

	// initialize the dialog
	if (FALSE == SHInitDialog(&sid)) {
		return FALSE;
	 }

	// show the first menubar, set the "current" handle
	ShowWindow(g_hWndMenuBar, SW_SHOW);

	// set the title bar
	VERIFY(SetWindowText(hWnd, (LPCTSTR)LoadString(g_hInst, IDS_MENU_TITLE, NULL, 0)));

	// set up spinner options, and SK button text
	hListBox = GetDlgItem(hWnd, IDC_LIST);

	// load the "Quit" string into the listbox
	lResult = SendMessage(hListBox, LB_ADDSTRING, 0,
	LoadString(g_hInst, IDS_MENU_QUIT, NULL, 0));

	if ( LB_ERR == lResult || LB_ERRSPACE == lResult ) {
		return FALSE;
	 }
	// load the "Uncheck" string

	lResult = SendMessage(hListBox, LB_ADDSTRING, 0,
	LoadString(g_hInst, IDS_MENU_UNCHECK, NULL, 0));
	if ( LB_ERR == lResult || LB_ERRSPACE == lResult ) {
		return FALSE;
	 }
	// set the initial selection of the listbox
	if ( LB_ERR == SendMessage(hListBox, LB_SETCURSEL, 0, 0) ) {
		return FALSE;
	 }

	// set button flags
	g_fChecked_Sk = FALSE;
	g_fChecked_Swap = FALSE;
	g_fChecked_Quit = FALSE;

	g_uiSk_Id = IDM_MENU_QUIT;

	return TRUE;
}


/**
 * @brief   Process necessary changes to menu before it pops up.
 */
BOOL OnMenuPopup( const HWND hWnd, const WPARAM wParam )
 {
	if ( g_fChecked_Quit ) {
		EnableMenuItem( (HMENU)wParam, IDM_MENU_QUIT, MF_BYCOMMAND | MF_GRAYED );
	 }
	else {
		EnableMenuItem( (HMENU)wParam, IDM_MENU_QUIT, MF_BYCOMMAND | MF_ENABLED );
	 }
	return TRUE;
 }


/**
 * @brief   Process commands
 */
BOOL OnCommand( const HWND hWnd, const WPARAM wParam )
{
	switch LOWORD( wParam ) {
		case IDM_MENU_QUIT: // quit
			EndDialog(hWnd, 0);
			break;

		case IDM_MENU_UNCHECK: // "uncheck all" menu option was chosen
			UncheckAll(hWnd); 
			break;

		case IDC_LIST: // the spinner selection changed
			if ( LBN_SELCHANGE == HIWORD(wParam) ) {
				ProcessListBox(hWnd);
			 }
			break;

		case IDC_SK_CHECKBOX: // handle the checkboxes
		case IDC_SWAP_CHECKBOX:
		case IDC_QUIT_CHECKBOX:
			ProcessCheckBox(hWnd, wParam);
			break;

		case IDCANCEL: // user pressed the Back key... we close the dialog box
			EndDialog(hWnd, 0);
			break;

		case ID_WMBUNDLE_RESTART: {
			Request* request = new Request( _Bundle_METHOD_Restart );
			Message* message = new Message(request);
			message->setDestination( URI(":Bundles/WindowsMobile") );
			postMessage(message);
			break;
			}

		case ID_WMBUNDLE_DECLARECOMM: {
			Request* request = new Request( _CommunicatorService_METHOD_declare );
			Message* message = new Message(request);
			message->setDestination( URI(":Bundles/WindowsMobile") );
			postMessage(message);
			break;
			}

		case ID_WMBUNDLE_DIAGNOSTIC: {
			Request* request = new Request( _Bundle_METHOD_Diagnostic );
			Message* message = new Message(request);
			message->setDestination( URI(":Bundles/WindowsMobile") );
			postMessage(message);
			break;
			}

		case ID_NETWORK_INFORMATION: {
			//WoshKernel::getInstance()->network().
			MessageBox( hWnd, TEXT("TODO!\n\n\n\nTODO!!."), TEXT("WOSHCESRV Network"), MB_OK );
			break;
			}

		case ID_NETWORK_DISCONNECTALL: {
			Request* request = new Request( "TODO" );
			Message* message = new Message(request);
			message->setDestination( URI(":Network") );
			postMessage(message);
			break;
			}

		case ID_NETWORK_SENDDISCOVERY: {
			Request* request = new Request( _Discovery_METHOD_discover );
			Message* message = new Message(request);
			message->setDestination( URI(":Bundles/Discovery") );
			postMessage(message);
			break;
			}


		default:
			return FALSE;
	 }
	return TRUE;
 }

void postMessage( Message* message ) {
	message->setSource( URI(":WinCeForm") );
	SecurityManager::getCredentialImplicit().signMessage(message, NULL);
	BusCore.postMessage(message);
 }

void processBusMessages( const HWND hWnd )
 {
	if ( formDialogListener.msgQueue.isEmpty() )
		return;

	Message* message = formDialogListener.msgQueue.pop();
	if ( message == NULL || message->isEmpty() ) return;
	
	if ( message->getContent()->isResponse() ) {
		const Response* response = message->getContent()->asResponse();
		if ( response->getMethod() == _CommunicatorService_METHOD_declare ) {
			if ( WSUCCEEDED(response->getReturnValue()) )
				MessageBox( hWnd, TEXT("Communicator Service has been declared successfully."), TEXT("WOSHCESRV Comm"), MB_OK );
			else
				MessageBox( hWnd, TEXT("FAILED declaring Communicator Service."), TEXT("WOSHCESRV Comm"), MB_OK );
		 }
		else if ( response->getMethod() == _Bundle_METHOD_Diagnostic ) {
			string info = "";
			if ( response->hasData() && response->getData()->isKindOf<Variant>() ) {
				info += "\nInformations:\n";
				info += dynamic_cast<const Variant*>(response->getData())->toString();
			 }
			if ( WSUCCEEDED(response->getReturnValue()) )
				info = "Diagnosting of WindowsMobile bundle succeeded";
			else
				info = "Diagnosting of WindowsMobile bundle FAILED (" + Utilities::toString<int>(response->getReturnValue()) + ")";
			std::Wstring infow = ToWString(info);
			MessageBox( hWnd, infow.c_str(), TEXT("WOSHCESRV Comm"), MB_OK );
		 }
	 }

 }



/**
 * @brief   Handle changes in the state of the checkboxes.
 */
BOOL ProcessCheckBox( const HWND hWnd, const WPARAM wParam )
 {
	switch LOWORD(wParam) {
		case IDC_SK_CHECKBOX: // "Disable Softkey"
			if ( BN_CLICKED == HIWORD(wParam) && IsWindowEnabled(GetDlgItem(hWnd, IDC_SK_CHECKBOX)) ) {
				if (BST_CHECKED == SendDlgItemMessage(hWnd, IDC_SK_CHECKBOX, BM_GETCHECK, 0, 0))
					g_fChecked_Sk = TRUE;
				else
					g_fChecked_Sk = FALSE;
			 }
			ProcessSkCheckBox();
			break;



		case IDC_QUIT_CHECKBOX: // "Disable Options->Quit"
			if ( BN_CLICKED == HIWORD(wParam) && IsWindowEnabled(GetDlgItem(hWnd, IDC_QUIT_CHECKBOX)) ) {
				if (BST_CHECKED == SendDlgItemMessage(hWnd, IDC_QUIT_CHECKBOX, BM_GETCHECK, 0, 0))
					g_fChecked_Quit = TRUE;
				else
					g_fChecked_Quit = FALSE;
			 }
			break;

		default:
			break;
	 }
	return TRUE;
 }


/**
 * @brief   Unchecks all the checkboxes that have been checked.
 */
BOOL UncheckAll( const HWND hWnd )
 {
	// uncheck "Disable SK" 
	if (BST_CHECKED == SendDlgItemMessage(hWnd, IDC_SK_CHECKBOX, BM_GETCHECK, 0, 0)) {
		SendDlgItemMessage(hWnd, IDC_SK_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0);
		g_fChecked_Sk = FALSE;
		ProcessSkCheckBox();
	 }
	// uncheck "Swap" 
	if (BST_CHECKED == SendDlgItemMessage(hWnd, IDC_SWAP_CHECKBOX, BM_GETCHECK, 0, 0)) {
		SendDlgItemMessage(hWnd, IDC_SWAP_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0);
		g_fChecked_Swap = FALSE;
	 }
	// uncheck "Quit" 
	if (BST_CHECKED == SendDlgItemMessage(hWnd, IDC_QUIT_CHECKBOX, BM_GETCHECK, 0, 0)) {
		SendDlgItemMessage(hWnd, IDC_QUIT_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0);
		g_fChecked_Quit = FALSE;
	 }
	return TRUE;
 }


/**
 * @brief   Handles the enabling/disabling of Sk.
 */
BOOL ProcessSkCheckBox()
 {
	UINT uiCurSkId;
	TBBUTTONINFO buttonInfo;

	ZeroMemory(&buttonInfo, sizeof(TBBUTTONINFO));
	buttonInfo.cbSize = sizeof(TBBUTTONINFO);
	buttonInfo.dwMask = TBIF_STATE;

		uiCurSkId = g_uiSk_Id;

	buttonInfo.fsState = TBSTATE_INDETERMINATE;
	SendMessage(g_hWndMenuBar, TB_SETBUTTONINFO, uiCurSkId,(LPARAM)(LPTBBUTTONINFO)&buttonInfo);

	return TRUE;
 }


/**
 * @brief   Handles the change in selection of the listbox/spinner.
 */
BOOL ProcessListBox( const HWND hWnd ) 
 {
	HWND hListBox;
	TCHAR psz[80];
	UINT uiIndex = 0;
	TBBUTTONINFO buttonInfo;

	ZeroMemory(&buttonInfo, sizeof(TBBUTTONINFO));
	ZeroMemory(psz, sizeof(psz));

	hListBox = GetDlgItem(hWnd, IDC_LIST);
	uiIndex = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
	SendMessage(hListBox, LB_GETTEXT, uiIndex,(LPARAM)psz);

	buttonInfo.cbSize = sizeof(TBBUTTONINFO);
	buttonInfo.dwMask = TBIF_TEXT | TBIF_COMMAND;
	buttonInfo.pszText = psz;

	if ( !_tcscmp(psz, TEXT("Uncheck All")) ) {
		buttonInfo.idCommand = IDM_MENU_UNCHECK;
	 }
	else {
		buttonInfo.idCommand = IDM_MENU_QUIT;
	 }

	//  set the proper menubar's action Softkey

	SendMessage(g_hWndMenuBar, TB_SETBUTTONINFO, g_uiSk_Id,(LPARAM)(LPTBBUTTONINFO)&buttonInfo);
	g_uiSk_Id = buttonInfo.idCommand;
 

	return TRUE;
 }



